<?php
/** @noinspection PhpUnused */
declare (strict_types = 1);

namespace app\service\logic;

use app\constant\LogicConstant;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\Model;
use think\helper\Str;
use think\exception\ClassNotFoundException;

class BaseService
{
    /**
     * @var string
     */
    protected string $modelClassName = '';

    protected string $namespace = 'app\\model\\communal\\';

    /**
     * @return string|Model
     */
    public function resolveModelClassName()
    {
        $className = $this->modelClassName;
        if (!empty($className) && ($this->namespace || false !== strpos($className, '\\'))) {
            $class = false !== strpos($className, '\\') ? $className : $this->namespace . Str::studly($className);

            if (class_exists($class)) {
                return $class;
            }
        }

        throw new ClassNotFoundException("Model [$className] not found.");
    }

    /**
     * 获取要搜索的字段
     *
     * @return array
     */
    public function getSearchColumn()
    {
        $modelName = $this->resolveModelClassName();
        return $modelName::$searchColumn;
    }

    /**
     * 获取新增的字段
     *
     * @return array
     */
    public function getSaveColumn()
    {
        $modelName = $this->resolveModelClassName();
        return $modelName::$saveColumn;
    }

    /**
     * 获取更新的字段
     *
     * @return mixed
     */
    public function getUpdateColumn()
    {
        $modelName = $this->resolveModelClassName();
        return $modelName::$updateColumn;
    }

    /**
     * 获取更新的部分字段
     *
     * @return mixed
     */
    public function getItemColumn()
    {
        $modelName = $this->resolveModelClassName();
        return $modelName::$itemColumn;
    }

    /**
     * 根据条件获取列表
     *
     * @param $params
     * @param array $search_fields
     * @param array $search
     * @param array $with
     * @param null $eachCall
     * @param bool $isPage
     * @return array
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function getList($params, array $search_fields = [], array $search = [], $with = [], $eachCall = null, $isPage = true)
    {
        $modelName = $this->resolveModelClassName();
        list($page, $page_size) = $this->pageByParams($params);
        $order = $this->orderByParams($params);

        $query = $modelName::field($modelName::$column)
            ->with($with)
            ->withSearch($search_fields, $search)
            ->order($order);
        if ($isPage) {
            $query = $query->page($page, $page_size);
        }
        $query = $query->select();
        if (is_callable($eachCall)) {
            $query = $query->each($eachCall);
        }
        $list = $query->toArray();
        $total = $modelName::withSearch($search_fields, $search)->count();

        return [
            'items' => $list,
            'total' => $total,
        ];
    }

    /**
     * 详细情况...
     *
     * @param $params
     * @param array $with
     * @param null $eachCall
     * @return array|false|mixed|Model
     * @throws DataNotFoundException
     * @throws ModelNotFoundException
     */
    public function read($params,  $with = [], $eachCall = null)
    {
        $id = $params['id'];
        $modelName = $this->resolveModelClassName();
        $model = $modelName::field($modelName::$column)->with($with)->findOrFail($id);
        if (is_callable($eachCall)) {
            $model = call_user_func($eachCall, $model);
        }
        return $model;
    }

    /**
     * 根据条件获取数量
     *
     * @param array $search_fields
     * @param array $search
     * @return int
     */
    public function getCount(array $search_fields = [], array $search = [])
    {
        $modelName = $this->resolveModelClassName();
        return $modelName::withSearch($search_fields, $search)->count();
    }

    /**
     * 下拉菜单无分页
     *
     * @param $params
     * @param array $search_fields
     * @param array $search
     * @param string $label
     * @param string $value
     * @return array
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function getOptions($params, array $search_fields = [], array $search = [], $label = 'name', $value = 'id')
    {
        $modelName = $this->resolveModelClassName();
        $isSearch = $params['search'] ?? false;
        $isClear = $params['clear'] ?? false;
        $order = $this->orderByParams($params);

        $options = $modelName::field($modelName::$column)
            ->withSearch($search_fields, $search)
            ->order($order)
            ->select()
            ->toArray();

        return $this->amisOptions($options, $label, $value, $isSearch, $isClear);
    }

    /**
     * 创建
     *
     * @param $params
     * @return Model
     */
    public function create($params)
    {
        $modelName = $this->resolveModelClassName();
        return $modelName::create($params);
    }

    /**
     * 查找单挑记录
     *
     * @param $params
     * @return array|mixed|Model
     * @throws DataNotFoundException
     * @throws ModelNotFoundException
     */
    public function getSimpleDetail($params)
    {
        $modelName = $this->resolveModelClassName();
        return $modelName::findOrFail($params['id']);
    }

    /**
     * 修改
     *
     * @param $params
     * @return array|mixed|Model
     * @throws DataNotFoundException
     * @throws ModelNotFoundException
     */
    public function item($params)
    {
        $model = $this->getSimpleDetail($params);
        $model->save($params);
        return $model;
    }

    /**
     * 单项删除
     *
     * @param $params
     * @return bool
     * @throws DataNotFoundException
     * @throws ModelNotFoundException
     */
    public function delete($params)
    {
        $model = $this->getSimpleDetail($params);
        return $model->delete();
    }

    /**
     * 批量删除
     *
     * @param $params
     * @return bool
     */
    public function batchDelete($params)
    {
        $modelName = $this->resolveModelClassName();
        $ids = explode(',', (string)$params['ids']);

        return $modelName::destroy(function ($query) use ($ids) {
            $query->whereIn('id', $ids);
        });
    }

    /**
     * 分页参数
     *
     * @param $params
     * @return int[]
     */
    public function pageByParams($params)
    {
        $page = isset($params['page']) && !empty($params['page']) ? (int)$params['page'] : 1;
        $pageSize = isset($params['page_size']) && !empty($params['page_size']) ? (int)$params['page_size'] : 1000;

        return [$page, $pageSize];
    }

    /**
     * 排序参数
     *
     * @param $params
     * @param string $column
     * @param string $type
     * @return array|string[]
     */
    public function orderByParams($params, string $column = 'id', string $type = 'desc')
    {
        $orderField =  isset($params['orderBy']) && !empty($params['orderBy']) ? $params['orderBy'] : $column;
        $order =  isset($params['orderDir']) && !empty($params['orderDir']) ? $params['orderDir'] : $type;

        return [$orderField => $order];
    }

    /**
     * 排序方式map
     *
     * @param $params
     * @return string
     */
    public function orderDirMap($params)
    {
        $dir = 'desc';
        if (isset($params['order_dir']) && 1 == $params['order_dir']) {
            $dir = 'asc';
        }
        return $dir;
    }

    /**
     * 根据父子字段获取树状
     *
     * @param $children
     * @param int $parent
     * @param string $childColumn
     * @param string $parentColumn
     * @return array
     */
    public function getTreeByParentColumn($children, int $parent = 0, string $childColumn = 'id', string $parentColumn = 'pid')
    {
        $result = [];
        foreach ($children as $item) {
            if ($item[$parentColumn] == $parent) {
                $item['children'] = $this->getTreeByParentColumn($children, $item[$childColumn], $childColumn, $parentColumn);
                $result[] = $item;
            }
        }

        return $result;
    }

    /**
     * amis form select options 处理
     *
     * @param $options
     * @param string $label
     * @param string $value
     * @param false $search
     * @param false $clear
     * @return array
     */
    public function amisOptions($options, $label = 'name', $value = 'id', $search = false, $clear = false)
    {
        $result = [];
        !$search ? : array_unshift($result, ['label' => $search,'value' => '']);
        !$clear ? : array_unshift($result, ['label' => $clear,'value' => 0]);

        foreach ($options as $option) {
            $result[] = [
                'label' => $option[$label],
                'value' => $option[$value],
            ];
        }
        return $result;
    }

    /**
     * amis 日志时间线
     *
     * @param $data
     * @return array
     */
    protected function amisLogTimeline($data)
    {
        $result = [];
        foreach ($data as $item) {
            $title = [];
            $temp['time'] = $item['created_at'];
            $tt = [];
            $tt[] = [
                'type' => 'tpl',
                'tpl' => "<div class='text-black mb-2 font-bold'>" . $item['title'] . '</div>',
            ];
            if (isset($item['log_json']['relation_data']) && !empty($item['log_json']['relation_data'])) {
                $relationData = $item['log_json']['relation_data'];
                foreach ($relationData as $ii) {
                    switch ($ii['data_type']) {
                        case LogicConstant::LOG_DATA_TYPE_ONE:
                            $tt[] = [
                                'type' => 'tpl',
                                'tpl' => "<div class='text-gray-500 mb-2'>" . $ii['data'] . '</div>',
                            ];
                            break;
                        case LogicConstant::LOG_DATA_TYPE_TWO:
                            if (LogicConstant::LOG_DATA_LOGIC_TYPE_THREE == $ii['data_logic_type']) {
                                $tt[] = [
                                    'type' => 'tpl',
                                    'tpl' => "<div class='text-gray-500 mb-2'>" . $ii['data']['key'] . '</div>',
                                ];
                            }
                            $tt[] = [
                                'type' => 'images',
                                'className' => 'mb-2',
                                'enlargeAble' => true,
                                'value' => $ii['data']['value']
                            ];
                            break;
                    }
                }
            }
            $tt[] = [
                'type' => 'tpl',
                'tpl' => "<div class='text-gray-300 text-sm'>" . '操作人: ' . $item['operator'] . '</div>',
            ];
            $title[] = $tt;
            $temp['title'] = $title;
            $result[] = $temp;
        }

        return $result;
    }

    /**
     * @param $type
     * @return string
     */
    public function getPaymentTypeMap($type)
    {
        $payment = [1 => '微信支付', 2 => '支付宝支付'];
        return $payment[$type] ?? '其他支付';
    }
}
